package com.to8to.autotask.lundan;

import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Splitter;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
import com.to8to.autotask.util.DBUtil;
import com.to8to.commons.mongo.DBParam;
import com.to8to.commons.mongo.MongoClientBase;
import com.to8to.commons.utils.DateUtil;
import com.to8to.commons.utils.GeoUtil;
import com.to8to.commons.utils.Object2Json;
import com.to8to.commons.utils.StringUtil;

public class ProjectDispatcher
{

    public static Logger logger = LoggerFactory.getLogger(ProjectDispatcher.class);

    public DBParam dbparam = new DBParam("192.168.1.57:27017", null, null, "dispatch");

    public MongoClientBase mongo = new MongoClientBase(dbparam);

    public DBParam dbparam_scene = new DBParam("192.168.1.57:27017", null, null, "diaryv2_test");

    public MongoClientBase mongo_scene = new MongoClientBase(dbparam_scene);

    public Map<Integer, Company> companyMap = new HashMap<Integer, Company>();

    public int LiangFangDayLimit = 180;

    public double MinimalBalanceA = 298;

    public double MinimalBalance = 198;

    public Map<Integer, Project> yid2biao = new HashMap<Integer, Project>();

    public Map<Integer, RoundRobinQueue<Integer>> commid2contractorqueue = new HashMap<Integer, RoundRobinQueue<Integer>>(); //楼盘承包公司 

    public Connection conn = null;

    public ObjectMapper mapper = new ObjectMapper();

    public Map<String, Double> weights = new HashMap<String, Double>();

    {
        try
        {
            conn = DBUtil.getConnection();
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }

        weights.put("distance", 0.2);

        weights.put("doubei", 0.2);

        weights.put("monthlylimit", 0.2);

        weights.put("hitsrate", 0.2);

        weights.put("gongdi", 0.15);

        weights.put("style", 0.05);
    }

    public Company getCompany(int id, boolean createIfNotExist)
    {
        Company company = companyMap.get(id);

        if (company == null && createIfNotExist)
        {
            company = new Company();

            company._id = id;

            companyMap.put(id, company);
        }

        return company;
    }

    public List<String> workingdays(int dayoff)
    {
        List<String> results = new ArrayList<String>();

        Date now = new Date();

        Date end = DateUtil.moveDay(now, LiangFangDayLimit);

        List<Date> dates = DateUtil.listDates(now, end);

        if (dayoff >= 1 && dayoff <= 7)
        {
            for (Date d : dates)
            {
                int weekday = DateUtil.getWeekByDate(d);
                weekday--;
                if (weekday == 0)
                    weekday = 7;

                if (weekday != dayoff)
                {
                    String txt = DateUtil.format(d, "yyyy-MM-dd");
                    results.add(txt);
                }
            }
        }
        else
        {
            for (Date d : dates)
            {
                String txt = DateUtil.format(d, "yyyy-MM-dd");
                results.add(txt);
            }
        }

        return results;
    }

    public int sgzz(String text)
    {
        String tmp = text.replace("级", "");

        tmp = StringUtil.Cn2Num(tmp);

        if (StringUtil.isNumeric(tmp))
            return Integer.parseInt(tmp);

        return 0;
    }

    public void scan_to8to_fcom()
    {
        logger.info("scan to8to_fcom(公司基本信息) ... start!");
        try
        {

            Statement stmt = conn.createStatement();

            ResultSet rs =
                stmt.executeQuery("SELECT id,cancost,monthlylimit,aptrank,kbpf,dayoff,upperlimit"
                    + ",have_tbnums,have_tbnums_2,have_tbnums_3,have_tbnums_4,have_tbnums_5,have_tbnums_6,have_tbnums_7 FROM to8to_fcom");

            while (rs.next())
            {

                int id = rs.getInt("id");

                double cancost = rs.getDouble("cancost");

                int monthlylimit = rs.getInt("monthlylimit");

                String aptrank = rs.getString("aptrank");

                int rank = sgzz(aptrank);

                double kbpf = rs.getDouble("kbpf");

                int dayoff = rs.getInt("dayoff");

                int have_tbnums = rs.getInt("have_tbnums");
                int have_tbnums_2 = rs.getInt("have_tbnums_2");
                int have_tbnums_3 = rs.getInt("have_tbnums_3");
                int have_tbnums_4 = rs.getInt("have_tbnums_4");
                int have_tbnums_5 = rs.getInt("have_tbnums_5");
                int have_tbnums_6 = rs.getInt("have_tbnums_6");
                int have_tbnums_7 = rs.getInt("have_tbnums_7");

                int upperlimit = rs.getInt("upperlimit");

                Company company = getCompany(id, false);

                if (company != null)
                {
                    company.balance = cancost;

                    company.monthlylimit = monthlylimit;

                    if (monthlylimit > 0)
                    {
                        company.class_a = true;
                        if (company.balance >= MinimalBalanceA)
                            company.has_balance = true;
                    }
                    else if (company.balance >= MinimalBalance)
                        company.has_balance = true;

                    company.koubei = kbpf;

                    company.aptrank = rank;

                    if (dayoff >= 1 && dayoff <= 7)
                        company.dayoff = dayoff;

                    if (have_tbnums > 0)
                        company.tbnums.put("1", have_tbnums);

                    if (have_tbnums_2 > 0)
                        company.tbnums.put("2", have_tbnums_2);

                    if (have_tbnums_3 > 0)
                        company.tbnums.put("3", have_tbnums_3);

                    if (have_tbnums_4 > 0)
                        company.tbnums.put("4", have_tbnums_4);

                    if (have_tbnums_5 > 0)
                        company.tbnums.put("5", have_tbnums_5);

                    if (have_tbnums_6 > 0)
                        company.tbnums.put("6", have_tbnums_6);

                    if (have_tbnums_7 > 0)
                        company.tbnums.put("7", have_tbnums_7);

                    if (upperlimit == 0)
                        upperlimit = Integer.MAX_VALUE;

                    company.upperlimit = upperlimit;
                }
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("scan to8to_fcom(公司基本信息) ... finish!");
    }

    public void scan_to8to_subcom()
    {
        logger.info("scan to8to_subcom(公司位置信息) ... start!");

        try
        {

            Statement stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT uid,xaxis,yaxis FROM to8to_subcom WHERE ispass=1");

            while (rs.next())
            {

                int uid = rs.getInt(1);

                double xaxis = rs.getDouble(2);

                double yaxis = rs.getDouble(3);

                Company company = getCompany(uid, false);

                if (company != null)
                    company.locations.add(new GeoPoint(xaxis, yaxis));
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        logger.info("scan to8to_subcom(公司位置信息) ... finish!");
    }

    public void scan_to8to_zxb_order()
    {
        logger.info("scan to8to_zxb_order(轮单队列) ... start!");
        try
        {

            Splitter splitter = Splitter.on(",").omitEmptyStrings();

            Statement stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT cityid,areaid,pricelevel,cgate,head_order,end_order FROM to8to_zxb_order");

            while (rs.next())
            {

                int cityid = rs.getInt(1);

                int areaid = rs.getInt(2);

                int pricelevel = rs.getInt(3);

                int cgate = rs.getInt(4);

                String category = cityid + "_" + areaid + "_" + pricelevel + "_" + cgate;

                String head_order = rs.getString(5);

                String end_order = rs.getString(6);

                String comlist = head_order + "," + end_order;

                List<String> coms = splitter.splitToList(comlist);

                for (String com : coms)
                {
                    Integer comid = Integer.parseInt(com);

                    Company company = getCompany(comid, true);

                    company.categories.add(category);
                }
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("scan to8to_zxb_order(轮单队列) ... finish!");
    }

    public boolean isThisMonth(int time)
    {
        long ts = time * 1000L;

        Date date = new Date(ts);

        Date first = DateUtil.getMonthsFirstDay(new Date());

        return date.getMonth() == first.getMonth() && date.getYear() == first.getYear();
    }

    public boolean isToday(int time)
    {
        long ts = time * 1000L;

        Date now = new Date();

        Date date = new Date(ts);

        String nowStr = DateUtil.format(now, "yyyy-MM-dd");

        String dateStr = DateUtil.format(date, "yyyy-MM-dd");

        return nowStr.compareTo(dateStr) == 0;
    }

    public void scan_to8to_yuyue_apply()
    {
        logger.info("scan to8to_yuyue_apply ... start!");
        try
        {
            Statement stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT yid,biao,pricelevel FROM to8to_yuyue_apply");

            while (rs.next())
            {

                int yid = rs.getInt("yid");

                int biao = rs.getInt("biao");

                int pricelevel = rs.getInt("pricelevel");

                Project p = new Project();
                p.id = yid;
                p.biao = biao;
                p.pricelevel = pricelevel;
                yid2biao.put(yid, p);
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("scan to8to_yuyue_apply ... finish!");
    }

    public void scan_to8to_yuyue_apply_ext()
    {
        logger.info("scan to8to_yuyue_apply_ext ... start!");

        try
        {
            Splitter splitter = Splitter.on(",").omitEmptyStrings();

            Statement stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT yid,ftime,struid FROM to8to_yuyue_apply_ext WHERE isassign=1");

            while (rs.next())
            {

                int yid = rs.getInt("yid");

                int ftime = rs.getInt("ftime");

                String struid = rs.getString("struid");

                List<String> comids = splitter.splitToList(struid);

                for (String com : comids)
                {
                    Integer comid = Integer.parseInt(com);

                    Company company = getCompany(comid, false);

                    if (company != null)
                    {
                        if (isToday(ftime))
                            company.daily_num++;

                        Project p = yid2biao.get(yid);
                        if (p != null)
                        {
                            if (isThisMonth(ftime))
                            {
                                company.month_num++; //本月分配的项目数
                                if (p.biao == 0) //本月分配的非优质项目数
                                    company.month_poor_num++;
                            }

                            Integer price_num = company.price_num.get(p.pricelevel + "");
                            if (price_num == null)
                                price_num = 0;
                            price_num++;

                            company.price_num.put(p.pricelevel + "", price_num); //该价位段的分配数
                        }
                        company.total_num++; //总分配数
                    }
                }
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("scan to8to_yuyue_apply_ext ... finish!");
    }

    public void scan_to8to_jj_smt_zb()
    {
        logger.info("scan to8to_jj_smt_zb(中标信息) ... start!");

        try
        {
            Statement stmt = conn.createStatement();

            ResultSet rs = stmt.executeQuery("SELECT yid,uid FROM to8to_jj_smt_zb WHERE chuli = 2");

            while (rs.next())
            {

                int yid = rs.getInt("yid");

                int uid = rs.getInt("uid");

                Company company = getCompany(uid, false);

                if (company != null)
                {
                    company.total_hits++;

                    Project p = yid2biao.get(yid);
                    if (p != null)
                    {
                        Integer price_hits_num = company.price_hits.get(p.pricelevel + "");
                        if (price_hits_num == null)
                            price_hits_num = 0;
                        price_hits_num++;
                        company.price_hits.put(p.pricelevel + "", price_hits_num); //该价位段的中标数
                    }
                }
            }

            DBUtil.releaseSource(rs, stmt, null);

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("scan to8to_jj_smt_zb(中标信息) ... finish!");
    }

    public void compute_ratios()
    {
        logger.info("计算中标率、非优质项目占比 ... start!");

        for (Company com : companyMap.values())
        {
            if (com.month_num > 0) //本月非优质项目占比
            {
                com.month_poor_ratio = (double) com.month_poor_num / (double) com.month_num;
                if (com.class_a && com.month_poor_ratio >= 0.3)
                    com.month_poor_baohe = true;
            }

            if (com.total_num > 0) //总中标率
                com.total_hits_ratio = (double) com.total_hits / (double) com.total_num;

            for (String k : com.price_num.keySet())
            {
                int num = com.price_num.get(k);

                Integer hits = com.price_hits.get(k);

                if (hits != null)
                {
                    double ratio = hits.doubleValue() / num;
                    com.price_hits_ratio.put(k, ratio);
                }
            }
        }

        logger.info("计算中标率、非优质项目占比 ... finish!");
    }

    public void scan_scene_data()
    {
        logger.info("scan scene(工地数据) ... start!");

        BasicDBObject q = new BasicDBObject("com_id", new BasicDBObject("$ne", 0)).append("status", 1);
        BasicDBObject fields =
            new BasicDBObject("_id", 1).append("com_id", 1).append("style", 1).append("comm_id", 1).append("town_id", 1).append("city_id", 1);

        DBCursor c = mongo_scene.cursor("scene", q, fields, null, 0, 0);

        while (c.hasNext())
        {
            BasicDBObject obj = (BasicDBObject) c.next();
            int com_id = obj.getInt("com_id");

            Company com = getCompany(com_id, false);

            if (com == null)
                continue;

            BasicDBList list = (BasicDBList) obj.get("style");

            if (list != null)
                for (Object style : list)
                {
                    int n = Integer.parseInt(style.toString());
                    if (n > 0)
                        com.styles.add(n);
                }

            int city_id = obj.getInt("city_id");

            int town_id = obj.getInt("town_id");

            int comm_id = obj.getInt("comm_id");

            if (city_id > 0 && town_id > 0 && comm_id > 0)
            {
                String k = city_id + "_" + town_id;

                Set<Integer> gongdiSet = com.gongdis.get(k);

                if (gongdiSet == null)
                {
                    gongdiSet = new HashSet<Integer>();

                    com.gongdis.put(k, gongdiSet);
                }

                gongdiSet.add(comm_id);
            }
        }

        c.close();

        logger.info("scan scene(工地数据) ... finish!");
    }

    public void store()
    {
        logger.info("store company info ... start!");

        for (Company company : companyMap.values())
        {
            String json = Object2Json.toJsonString(company);
            DBObject obj = (DBObject) JSON.parse(json);
            mongo.save("company", obj);
        }

        logger.info("store company info ... finish!");
    }

    /**
     * 打分和排序
     */
    public void rank()
    {
        logger.info("扫描两张项目表（待轮单） ... 开始!");

        List<Project> projects_to_diapatch = new LinkedList<Project>();

        try
        {
            Set<Integer> project_ids = new HashSet<Integer>();

            Map<Integer, Project> map = new HashMap<Integer, Project>();

            {
                Statement stmt = conn.createStatement();

                int now = (int) (System.currentTimeMillis() / 1000L);

                ResultSet rs = stmt.executeQuery("SELECT yid, toupai_uid, cgate FROM to8to_yuyue_apply_ext WHERE isassign=0 AND ftime < " + now);

                while (rs.next())
                {
                    int yid = rs.getInt("yid");
                    int cgate = rs.getInt("cgate");

                    Project p = new Project();

                    p.id = yid;

                    p.cgate = cgate;

                    map.put(yid, p);

                    project_ids.add(yid);
                }

                DBUtil.releaseSource(rs, stmt, null);
            }

            {
                Statement stmt = DBUtil.getConnection().createStatement();

                ResultSet rs =
                    stmt.executeQuery("SELECT yid,biao,pricelevel,cityid,areaid,delaytime,styleid,sg_zz,sid,baidumap"
                        + " FROM to8to_yuyue_apply WHERE ispass=1 ORDER BY puttime ASC");

                while (rs.next())
                {
                    int yid = rs.getInt("yid");

                    if (!project_ids.contains(yid))
                        continue;

                    Project project = map.get(yid);

                    int biao = rs.getInt("biao");

                    int pricelevel = rs.getInt("pricelevel");

                    int cityid = rs.getInt("cityid");

                    int areaid = rs.getInt("areaid");

                    int delaytime = rs.getInt("delaytime");

                    int styleid = rs.getInt("styleid");

                    String sg_zz = rs.getString("sg_zz");

                    int sgzz = sgzz(sg_zz);

                    int comm_id = rs.getInt("sid");

                    project.areaid = areaid;
                    project.biao = biao;
                    project.cityid = cityid;
                    project.comm_id = comm_id;
                    project.delaytime = delaytime;
                    project.pricelevel = pricelevel;
                    project.sgzz = sgzz;
                    project.styleid = styleid;

                    String baidumap = rs.getString("baidumap");

                    if (baidumap.contains(","))
                    {
                        String s1 = StringUtils.substringBefore(baidumap, ",");
                        String s2 = StringUtils.substringAfter(baidumap, ",");

                        double xaxis = Double.parseDouble(s1);

                        double yaxis = Double.parseDouble(s2);

                        project.xaxis = xaxis;

                        project.yaxis = yaxis;
                    }

                    projects_to_diapatch.add(project);
                }

                DBUtil.releaseSource(rs, stmt, null);
            }

        }
        catch (SQLException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("扫描两张项目表（待轮单） ... 完成!");

        for (Project p : projects_to_diapatch)
        {
            rank(p);
        }
    }

    public void rank(Project p)
    {

        BasicDBObject query = new BasicDBObject();

        String category = p.cityid + "_" + p.areaid + "_" + p.pricelevel + "_" + p.cgate;

        query.put("categories", category); //类别

        if (p.sgzz > 0)
            query.put("aptrank", new BasicDBObject("$gte", p.sgzz)); //施工资质要求

        if (p.delaytime > 0)
        {
            long ts = p.delaytime * 1000L;

            Date date = new Date(ts);

            int liangfangday = date.getDay();

            if (liangfangday == 0)
                liangfangday = 7;

            query.put("dayoff", new BasicDBObject("$ne", liangfangday)); //量房日不是工作日
        }

        BasicDBList or = new BasicDBList();

        or.add(new BasicDBObject("has_balance", true));

        or.add(new BasicDBObject("tbnums." + p.pricelevel, new BasicDBObject("$gte", 1)));

        query.put("$or", or); // 有余额或者消耗次数

        query.put("month_poor_baohe", false); // 非优质项目占比不超出 

        DBCursor c = mongo.cursor("company", query, null, null, 0, 0);

        while (c.hasNext())
        {
            BasicDBObject obj = (BasicDBObject) c.next();

            try
            {

                Company com = mapper.readValue(obj.toString(), Company.class);
                //计算距离： GeoUtil.distance(_lat1, _lon1, _lat2, _lon2)

            }
            catch (JsonParseException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (JsonMappingException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }

    public void score(Project p, Company com)
    {

        double score = 0;

        if (p.xaxis > 0 && p.yaxis > 0)
        {
            double min = Double.MAX_VALUE;
            for (GeoPoint pt : com.locations)
            {
                double dist = GeoUtil.distance(pt.x, pt.y, p.xaxis, p.yaxis);
                if (dist < min)
                    min = dist;
            }
            double subscore = Math.max(100 - 2.0 * min, 0);

            com.scores.put("distance", subscore);

            score += subscore;
        }

    }

    /**
     * 抢标
     */
    public void dispatch()
    {
        logger.info("扫描两张项目表（待轮单） ... 开始!");

    }

    /**
     * 扣轮标费
     */
    public void cost()
    {

    }

    public void dispatch(Project p)
    {

    }

    public void prepare()
    {
        long t1 = System.currentTimeMillis();

        scan_to8to_zxb_order();

        scan_to8to_subcom();

        scan_to8to_fcom();

        scan_to8to_yuyue_apply();

        scan_to8to_yuyue_apply_ext();

        scan_to8to_jj_smt_zb();

        compute_ratios();

        scan_scene_data();

        store();

        long t2 = System.currentTimeMillis();

        logger.info("time: " + ((t2 - t1) / 1000) + " sec");
    }

    public void print()
    {
        for (Company company : companyMap.values())
        {
            System.out.println(Object2Json.toJsonString(company));
        }
    }

    public void close()
    {
        DBUtil.releaseSource(null, null, conn);
    }

    public static void main(String[] args)
    {

        ProjectDispatcher test = new ProjectDispatcher();

        test.prepare();

        test.rank();

        test.dispatch();

        test.close();
    }

}
